package com.payment.service.impl;

import cn.hutool.core.util.BooleanUtil;
import com.alipay.v3.model.AlipayTradeRefundResponseModel;
import com.alipay.v3.model.RefundGoodsDetail;
import com.aliyun.pojo.pay.AliyunPayRefundParam;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.rabbitmq.producer.core.OrderProducer;
import com.payment.domain.dto.OrderPaymentDtoRefundDto;
import com.payment.domain.pojo.PaymentRecord;
import com.payment.domain.pojo.RefundRecord;
import com.payment.enums.PaymentStatus;
import com.payment.enums.RefundStatus;
import com.payment.mapper.RefundRecordMapper;
import com.payment.service.IPaymentRecordService;
import com.payment.service.IRefundRecordService;
import com.payment.service.PaymentServiceFactory;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 退款记录表 服务实现类
 * </p>
 *
 * @author 小杰大人
 * @since 2025-09-29
 */
@Service
@Slf4j
public class RefundRecordServiceImpl extends ServiceImpl<RefundRecordMapper, RefundRecord> implements IRefundRecordService {

    @Resource
    IPaymentRecordService iPaymentRecordService;

    @Resource
    PaymentServiceFactory paymentServiceFactory;

    @Resource
    OrderProducer orderProducer;

    @Override
    public RefundRecord querySelectByOrderNo(String orderNo) {
        return baseMapper.querySelectByOrderNo(orderNo);
    }

    @Override
    @Transactional
    public Boolean refund(OrderPaymentDtoRefundDto order) {
        boolean res = false;
        // 1: 查询交易订单
        PaymentRecord paymentRecord = iPaymentRecordService.getOne(new LambdaQueryWrapper<PaymentRecord>().eq(PaymentRecord::getOrderNo, order.getOrderNo()).eq(PaymentRecord::getOrderId, order.getId()));
        // 2：交易订单是否存在
        if (paymentRecord == null){
            log.error("订单退款 =》 订单：{} 不存在", order.getOrderNo());
            return res;
        }
        // 3：判断订单是否支付成功
        if (BooleanUtil.isFalse(iPaymentRecordService.queryPaymentResult(order.getOrderNo()))){
            log.error("订单退款 =》 订单：{} 未支付成功", paymentRecord.getOrderNo());
            return res;
        }
        // 4: 判断该笔订单是否已经退款
        boolean record = hasOrderRefundRecord(order.getOrderNo());
        if (record){
            // 退款记录存在，并且已经退款成功
            log.debug("订单退款 =》 [重复退款]订单：{} 已经退款成功", paymentRecord.getOrderNo());
            return true;
        }
        RefundRecord refundRecord = RefundRecord.builder()
                .orderId(order.getId())
                .orderNo(order.getOrderNo())
                .userId(order.getUserId())
                .refundAmount(paymentRecord.getPaymentAmount()) // 退款金额为支付金额
                .refundNo(order.getRefundNo())
                .refundReason(order.getReason())
                .refundStatus(RefundStatus.APPLYING.getCode())
                .paymentType(paymentRecord.getPaymentType())
                .build();
        this.save(refundRecord);
        // 5：将支付记录的支付状态改为退款中
        paymentRecord.setPaymentStatus(PaymentStatus.APPLYING.getCode());
        iPaymentRecordService.updateById(paymentRecord);
        // 6：发起退款
        AliyunPayRefundParam refundParam = new AliyunPayRefundParam(
                paymentRecord.getPaymentAmount(),
                order.getOrderNo(),
                paymentRecord.getTradeNo(),
                order.getReason(),
                order.getRefundNo());
        refundParam.setQuery_options(new String[]{"refund_detail_item_list"});  // // 设置查询选项
        RefundGoodsDetail goodsDetail = new RefundGoodsDetail();
        goodsDetail.setGoodsId(order.getCourseId().toString());
        goodsDetail.setRefundAmount(order.getCurPrice().toString());
        refundParam.setRefund_goods_detail(new RefundGoodsDetail[]{goodsDetail});   // 设置退款包含的商品列表信息
        // 发起支付宝退款
        AlipayTradeRefundResponseModel refundResponseModel = paymentServiceFactory.refund(refundParam);
        if (refundResponseModel == null){
            // 退款失败
            refundRecord.setRefundStatus(RefundStatus.FAIL.getCode());
            // 订单服务 告知订单退款失败
            orderProducer.orderRefundFail(order.getOrderNo());
        }else {
            // 退款成功
            refundRecord.setBuyerOpenId(refundResponseModel.getBuyerOpenId());   // 买家支付宝用户唯一标识
            refundRecord.setRefundStatus(RefundStatus.SUCCESS.getCode());
            refundRecord.setSendBackFee(new BigDecimal(refundResponseModel.getSendBackFee()));
            refundRecord.setTradeNo(refundResponseModel.getTradeNo());
            refundRecord.setCallbackTime(LocalDateTime.now());
            res = true;
            log.info("订单退款 =》 订单：{} 退款成功", order.getOrderNo());
            // 发送消息 告知订单服务 退款成功
            orderProducer.orderRefundSuccess(order.getOrderNo());
        }
        this.updateById(refundRecord);
        return res;
    }

    /**
     * 判断当前订单是否已经退款
     * @param orderNo
     * @return
     */
    private boolean hasOrderRefundRecord(String orderNo) {
        long count = this.count(new LambdaQueryWrapper<RefundRecord>().eq(RefundRecord::getOrderNo, orderNo).eq(RefundRecord::getRefundStatus, RefundStatus.SUCCESS.getCode()));
        return count < 0;
    }

    @Override
    public Byte queryRefundResult(String orderNo) {
        PaymentRecord paymentRecord = iPaymentRecordService.querySelectByOrderNo(orderNo);
        if (paymentRecord == null){
            log.error("查询订单退款 =》 订单：{} 不存在", orderNo);
            return null;
        }
        if (PaymentStatus.APPLYING.getCode() != paymentRecord.getPaymentStatus()){
            log.error("查询订单退款 =》 订单：{} 并未申请退款", orderNo);
            return null;
        }
        RefundRecord record = querySelectByOrderNo(orderNo);
        if (record == null){
            log.error("查询订单退款 =》 订单：{} 退款记录不存在", orderNo);
            return null;
        }
        return record.getRefundStatus();
    }

    @Override
    public List<RefundRecord> queryRefundRecord(String orderNo) {
        return this.list(new LambdaQueryWrapper<RefundRecord>().eq(RefundRecord::getOrderNo,orderNo).orderByDesc(RefundRecord::getCreateTime));
    }
}
